#include "dns.h"
#include <compat/sockinet.h>
#include <event2/event_compat.h>

#if (TARGET_OS == OS_WINDOWS)
	#include <event2/iocp-internal.h>
#endif



static void dns_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {

	dns_req_t * req = (dns_req_t *)arg;
	struct in_addr *addrs = (in_addr *)addresses;

	if (result != DNS_ERR_NONE || count == 0) {
		req->func(1, req->data, req, "");
	}
	else {

		for (int iloop = 0; iloop < count; iloop++) {
			//this inet_ntoa have a bug in the windows xp
			//i know
			char ip[32] = { 0x00 };
			os_inet_ntop(AF_INET,(const void *)(&addrs[iloop].s_addr),ip,32);
			if (ip) {
				req->func(0, req->data, req, ip);
			}
		}
	}
	req->end(0, req->data, req, "");
}

int dns_init(dns_t* dns, dns_thread_cb func, void* pdata) {

	retrtpv(dns, -1)

#if (TARGET_OS == OS_WINDOWS)
	evthread_use_windows_threads();
#elif (TARGET_OS == OS_POSIX)
	evthread_use_pthreads();
#elif (TARGET_OS == OS_MAC)
	evthread_use_pthreads();
#endif

	dns->base = event_base_new();
	if (!dns->base)
		return -1;

	
#if (TARGET_OS == OS_WINDOWS)
	struct event_iocp_port *port = NULL;
	event_base_start_iocp_(dns->base, 1);
	port = event_base_get_iocp_(dns->base);
#endif


	//1 = fail ???
	dns->dnsbase = evdns_base_new(dns->base, EVDNS_BASE_INITIALIZE_NAMESERVERS);
	if (!dns->dnsbase) {
		dns->dnsbase = evdns_base_new(dns->base, 0);
		evdns_base_nameserver_ip_add(dns->dnsbase, "8.8.8.8");
		if (!dns->dnsbase) {
			return -1;
		}
	}

	int r = 0;
	r = evdns_base_load_hosts(dns->dnsbase, NULL);
	retrtnpv(r, -1)

	r = evdns_base_set_option(dns->dnsbase, "timeout", "1");
	retrtnpv(r, -1)

	r = evdns_base_set_option(dns->dnsbase, "getaddrinfo-allow-skew", "0.2");
	retrtnpv(r, -1)

	r = evdns_base_set_option(dns->dnsbase, "max-timeouts", "1");
	retrtnpv(r, -1)


	dns->cb = func;
	dns->data = pdata;

	return 0;
}

int dns_free(dns_t* dns) {

	retrtpv(dns, -1)

	if (dns->base != NULL) {
		event_base_loopexit(dns->base, NULL);
	}
	return 0;
}
int dns_addaddress(dns_t* dns, const char* addr) {

	retrtpv(dns, -1)

	int r = 0;
	evdns_base_nameserver_ip_add(dns->dnsbase, addr);
	retrtpv(r, -1)

	return 0;
}

int dns_req(dns_t* dns, dns_req_t* req) {

	retrtpv(dns, -1)
	retrtpv(req, -1)

	if (!dns->irun) {
		return 0;
	}

	req->handle = evdns_base_resolve_ipv4(dns->dnsbase, req->url, 0, dns_callback, req);
	if (!req->handle)
		return 0;

	req->dnsbase = dns->dnsbase;

	return 1;
}
int dns_canecl_req(dns_req_t* req) {
	
	retrtpv(req, -1)
	evdns_cancel_request(req->dnsbase,req->handle);
	return 1;
}


void onTime(int sock, short event, void *arg)
{

	retret(arg);
	dns_t* dns = (dns_t*)(arg);
	dns->cb(1, dns->data);
	dns->irun = 1;

	if (dns->time_ev != NULL)
		event_free(dns->time_ev);
	dns->time_ev = NULL;
}
static void do_Notify(dns_t* dns) {

	dns->time_ev = evtimer_new(dns->base, onTime, dns);
	struct timeval tv = { 0,1};
	event_add(dns->time_ev, &tv);
}
int runloop(dns_t* dns) {

	retrtpv(dns, -1)
	dns->irun = 0;
	do_Notify(dns);
	iosprintf("dns thread start\n");
	//event_base_dispatch(dns->base);
	event_base_loop(dns->base, EVLOOP_NO_EXIT_ON_EMPTY);
	iosprintf("dns thread end\n");

	dns->cb(0, dns->data);

	retrtpv(dns->dnsbase, -1)
	evdns_base_free(dns->dnsbase, 1);
	dns->dnsbase = NULL;

	event_base_free(dns->base);
	dns->base = NULL;

	return 1;
}